SQL이란 관계형 데이터베이스(이하 RDB)에 질의를 하기 위한 언어이다.
SQL은 관계형 모델을 기반으로 한 질의 언어이지만 관계형 모델을 충실하게 재현하지는 않는다. SQL은 매우 유연성이 높게 설계된 언어이므로 관계형 모델에 맞게 사용할 수도 있고, 반대로 전혀 다르게 사용할 수도 있다. 하지만 SQL은 관계형 모델을 기반으로 설계돼 있으므로 관계형 모델에 따른 연산이 가장 적합하다.
관계형 모델은 실제 세계의 데이터를 관계 라는 개념을 사용해 표현한 데이터 모델이다.
관계형 모델이 나타내는 데이터 모델은 설계의 의미가 아니고 “데이터를 어떻게 표현할까” 라는 개념의 이미다. ""ㅁㅁ라는 개념을 사용해 데이터를 표현해주세요"" 라고 정하는 것이 데이터 모델이며 관계형 모델은 그중 하나라고 할 수 있다.
KVS(Key-Value Store)처럼 키와 그에 해당하는 값의 형태로 데이터를 표현하는 것도 데이터 모델의 하나다.
관계형 모델을 이해하는 데 가장 중요한 개념이 관계(릴레이션)다.
SQL에 있어 릴레이션에 해당하는 것은 테이블이다.
관계형 모델에서 릴레이션은 제목(Heading)과 본체(Body)로 구성되 있으며, 제목은 속성(Attribute)이 n개 모인 집합이며, 이 속성은 이름과 데이터 형으로 되어 있다. 본체는 속성값의 집합인 행 또는 영어로 말하면 튜플(tuple)의 집합이다.
튜플에 포함된 속성값은 이름과 데이터 형이 제목에서 지정한 것과 서로 일치하지 않으면 안 된다.
릴레이션이란 튜플의 집합이고, 튜플은 모두 같은 n개의 속성값의 집합으로, 데이터 구성이 서로 같다.
튜플의 집합은 릴레이션의 본체이며 원래 의미는 본체와 제목의 쌍을 가진 관계라고도 한다.
튜플과 속성을 SQL 에서는 각각 행(row)과 열(column)이라고 한다.
집합은 수학에서 사용되는 개념으로 물건의 모임을 표현하는 개념이다. 집합에 포함된 각 물건을 요소나 원소(Element)라고 한다. 요소에는 특별한 제약이 없으며 물건의 모임을 처리하기 위한 범용적인 구조로써 집합을 사용할 수 있다.
집합의 요소는 어떤 성질이든 상관 없지만 몇가지 조건을 충족해야한다.
어떤 요소가 집합에 포함돼 있는지 불정확한 요소 없이 판정할 수 있어야 한다.
집합의 요소는 더는 분해될 수 없다. e를 분해한 일부는 e와는 일치하지 않으므로 e ∈ S
라는 판정에 아무런 영향을 미치지 않는다.
관계형 모델은 집합론에 기인하는 데이터 모델이다. 집합이 무엇인지 이해하는 것이 관계형 모델을 이해하는데 있어서 중요하다.
집합에서 알 수 없는 것을 포함하지 않는 것은 집합의 한 종류인 릴레이션에 NULL을 포함할 수 없다는 의미다. NULL은 값이 아니고 요소가 무엇인지 모르는, 즉 알 수 없는 값임을 나타내는 표식이다.
집합에는 유한집합과 무한집합이라는 종류가 있다. 관계형 모델이 다루는 것은 유한집합 뿐이다.
단순하게 릴레이션으로 데이터를 표현하는 것만으로는 도움이 안되고, 데이터는 그에 대한 연산(또는 조작)과 세트로 사용될 때 의미가 있다.
데이터를 릴레이션이라고 표현한다면 그에 대한 연산은 쿼리(질의)다. 관계형 모델은 릴레이션 단위로 다양한 연산을 사용해 질의를 수행하는 데이터 모델이다. 릴레이션을 사용한 연산을 수행하므로 관계형 모델이라고 부른다.
릴레이션은 본질적으로 집합이며 그에 대한 연산도 집합론을 바탕으로 하고 있다. 릴레이션 내의 튜플이 모두 같은 구조, 즉 같은 이름, 같은 데이터형을 가지므로 일반적인 집합에는 없는 관계형 모델 특유의 연산이 많다.
제한은 어떤 릴레이션들 중에 특정 조건에 맞는 튜플을 포합한 릴레이션을 반환한다. 제한을 실행한 결과는 릴레이션의 부분집합이라고 할 수 있다.
프로젝션은 어떤 릴레이션에서 특정 속성만 포함하는 릴레이션을 반환한다. 어떤 릴레이션에서 특정 속성으로 프로젝션 하면 중복된 요소가 있을 경우 집합은 중복되는 요소는 포함할 수 없으므로 중복이 발생한 경우 같은 튜플로 간주한다.
확장(Extend)은 프로젝션과는 반대로 속성을 늘리는 동작이다. 대부분 새로운 속성값은 기존의 속성값을 이용해 계산한다.
속성명 변경(Rename)은 단순히 속성의 이름을 변경하는 동작이다. 실제로는 주로 확장한 속성에 대해 명칭을 부여할 때 사용한다.
합집합은 두 개의 릴레이션에 포함된 모든 튜플로 구성된 릴레이션(합집합)을 반환한다. 두 개의 릴레이션에 공통된 속성값이 포함됐다면 중복 값이 제거된 상태가 된다.
교집합은 두 개의 릴레이션에 모두 포함된 릴레이션을 반환한다.
차집합은 두 개의 릴레이션 중에 한쪽의 릴레이션에만 포함되어 있는 튜플로 구성된 릴레이션을 반환한다. 차집합은 어느 쪽의 릴레이션을 기준으로 정하는지에 따라 결과가 달라진다.
곱집합은 두 개의 릴레이션에 있는 튜플을 각각 조합한 릴레이션을 반환한다. 이때 릴레이션의 제목은 두 개의 릴레이션의 제목이 가진 속성을 전부 포함한다.
결합은 공통된 속성을 가진 두 개의 릴레이션에서 공통된 속성값이 같은 튜플끼리 조합한 릴레이션을 반환한다.
결과적으로 반환되는 튜플은 두 개의 릴레이션에서 공통된 속성에 관해 같은 값이 존재하는 것뿐이다. 즉 일치하지 않는 값이 존재하지 않는 튜플은 결과에서 제외된다. 이와 같은 형태의 결합을 SQL에서는 내부조인(INNER JOIN)이라고 한다.
덧붙혀 교집합과 곱집합은 결합의 특수한 예다. 교집합은 두 개의 릴레이션에 포함되는 속성이 전부 공통인 경우이고 반대로 곱집하는 공통의 속성이 존재하지 않는 경우다.
만약 릴레이션에 NULL이 포함돼 있으면 관계형 모델은 성립하지 않는다. NULL은 값을 모르는 상태를 나타내는 표식이다. 따라서 NULL이 포함돼 있으면 릴레이션 연산 결과가 항상 같아지지 않는다.
NULL은 관계형 모델의 근본을 뒤집는 불안전한 요소다.
관계형 모델에서 중요한 것은 릴레이션을 사용한 연산 결과가 릴레이션이 되는 것이다. 이처럼 입력과 출력이 같은 데이터 구조를 가진 성질을 클로저(폐쇄)라고 한다.
이와같은 데이터 구조는 연산 결과를 새롭게 입력해 꼬리에 꼬리를 무는 것처럼 연산을 기술하여 복잡한 연산을 표현할 수 있다. 그렇기 때문에 연산 결과가 릴레이션이라면 그 결과를 다른 릴레이션과 조합해 연산할 수 있다.
릴레이션의 연산만을 이용해 복잡한 연산을 표현할 수 있다는 점이 관계형 모델의 진면목이라고 할 수 있다.
데이터 형식이란 각 속성이 어떤 값을 가질 것인지를 말한다.
관계형 모델 자신은 “어떤 데이터 형식을 사용해야 할까?” 라고 결정하지 않는다. 관계형 모델은 문자 그대로 모델이므로 어떻게 사용할 수 있는지가 정해져 있을 뿐 어떻게 사용해야 한다는 모델을 사용하는 응용 프로그램이 정해야 한다.
변수란 값을 대입할 수 있는 그릇이다. 변수의 내용은 프로그램이 실행되면서 끊임없이 변한다. 값은 여러 종류가 있지만 각각의 값이 갖는 의미는 일반적이다. 어떤 값이 다른 의미나 양을 가지지 않는다.
컴퓨터가 표현할 수 있는 데이터는 변경할 수 있는 한계가 있기 때문에 변수에 대입할 수 있는 값은 한정되 있다.
데이터 형식은 그 변수에 대입할 수 있는 값의 유한집합이다.
관계형 모델에서 데이터 형식은 도메인이라고 한다. 값은 그 집합의 요소 하나하나이고 변수는 어떤 시점에 그 집합에서 요소를 한 개 선택한 것으로 해석한다. 집합의 요소(값)에는 변화가 없지만 어떤 요소를 선택할 것인가(변수)는 시시각각 변할 것이다. 그 집합 전체를 도메인이라고 한다.
도메인이 유한집합이라는 것은 튜플이 취득할 수 있는 값을 그 유한집합의 곱집합으로 나타낼 수 있다는 말이다.
튜플은 제목에 정의된 속성의 곱집합 중 한개의 요소다. 릴레이션은 속성의 도메인의 곱집합에서 특정 튜플만 선택해 구성한 집합이다.
관계형 모델은 릴레이션을 구성하는 제목, 본체, 튜플뿐만 아니라 속성의 데이터 형식조차도 집합으로 되어 있다.
SELECT는 SQL에서 데이터를 조회하는 데 사용하는 유일한 명령이다. 질의 기능은 전부 SELECT에 들어 있다.
SELECT 컬럼의 목록
FROM 테이블의 목록
WHERE 검색 조건
위의 세 항목은 모두 각각 릴레이션의 대수 연산에 해당 하며, 컬럼의 목록은 Projection, 테이블의 목록은 곱집합(Product), 검색 조건은 제한(Restrict)이다.
연산이 평가되는 순서
밑의 쿼리를 보면서 같이 공부해보자
SELECT t1.c1, t1.c2, t2.c3
From t1 INNER JOIN t2
WHERE t1.c4 = t2.c5 AND t2.c6 < 100;
SELECT 문에서 항목들이 평가되는 순서와 실제로 RDB에 의해 어떤 순서로 실행되는지는 관계가 없다. RDB에서는 옵티마이저가 최적화를 하여 처리를 생략하거나 실행 순서를 바꾼다.
관계형 모델에서는 새로운 속성(SQL에서는 컬럼)을 추가하는 작업을 확장(Extend)라고 한다. 평가는 프로젝션 전에 수행된다.
사실 관계형 모델에는 갱신이라는 개념이 존재하지 않는다. 릴레이션은 값이기 때문에 갱신하는 것은 불가능 하다.
SQL 에서는 테이블 내의 값을 변경할 수 있다. INSERT는 행을 추가하지만, 행을 추가해 테이블의 값(릴레이션)이 바뀌는 것처럼 보인다.
위의 모순은 테이블이 값과 변수라는 양쪽의 역할을 하기 때문이다. 관계형 모델에서 릴레이션을 저장하는 변수는 Relvar(Relation Variable, 관계 변수)라고 한다. 즉 SQL에서 테이블의 갱신 처리는 Relvar의 역할로 테이블에 해당된 릴레이션의 값을 변경하는것이다.
INSERT는 Relvar의 값( = 릴레이션)을 해당 릴레이션에 새롭게 INSERT 할 튜플(행)을 추가하고 릴레이션과 바꾸는 작업을 한다. 관계형 모델에서 릴레이션의 연산은 입력도 출력도 릴레이션이다. R:= R ∪ {T}
DELETE는 차집합이라고 할 수 있다.
DELETE FROM t WHERE c1 = 100;
위의것을 관계형 모델로 표현하면 전체 릴레이션(=Relvar에 대입되는 값)에서 WHERE 절의 조건인 c1 = 100에 해당하는 튜플의 집합(즉 전체의 릴레이션의 부분집합)이 되고 릴레이션의 차집합을 Relvar에 대입하는 것과 같다.
R:= R - {T}
UPDATE t SET c1 = 1 WHERE c2 = 123;
R:=(R-{T1})∪{T2}
SQL을 효과적으로 사용하기 위한 요령은 무엇보다도 모델에 맞게 사용하는 것이다.
릴레이션은 구조가 같은 튜플의 집합이다. 집합은 수학적 의미에서의 집합이다. 집합은 중복되지 않으므로 릴레이션도 마찬가지다.
SQL은 테이블에 같은 행이 있더라도 괜찮다. 기본키와 같은 유일성 제약이 있다면 테이블에 중복되는 행이 존재하지 않지만, 그렇지 않다면 가능하다. 즉 테이블은 원래 집합이 아니다. 테이블은 다중집합(Multiset)이라고 할 수 있다.
SQL 관계형 모델에 맞게 사용하려면 테이블을 집합처럼 사용해야 한다. 적어도 어딘가에 유일성 제약이 있어야한다.
집합은 요소 사이의 순서가 없다. 따라서 집합으로 정의된 릴레이션(의 본체), 튜플, 제목에 포함된 요소에는 순서가 없다.
하지만 SQL에는 순서가 있고, 컬럼은 정의된 순서대로 나열되고 행을 정렬할 수도 있다. 쿼리를 실행한 결과도 지정한 순서로 나열된다.
관계형 모델에 따라 SQL을 사용하려면 행이나 컬럼의 위치를 고려한 쿼리를 작성해서는 안 된다. 예를 들어 ROWNUM 이나 ORDER BY 1(1번째 컬럼을 기준으로 정렬)과 같은 기능은 피해야 한다.
릴레이션은 값이므로 갱신할 수 없다. 값을 갱신할 수 있는 것은 변수 뿐이다. 하지만 테이블은 값과 변수의 기능을 모두 겸한다.
트랜잭션은 SQL 사양의 일부이지만 관계형 모델과는 다른 독립적인 개념으로 관계형 모델에 포함되지 않는다.
관계형 모델과 트랜잭션은 다른 개념이지만 RDB를 사용하려면 양쪽을 바르게 이해하고 사용해야 한다.
두 가진는 상호 보완적인 관계이며 RDB에서 두개의 축이라고 할 수 있다.
관계형 모델에는 프로시저가 존재하지 않는다. 따라서 커서를 루프로 처리하는 작업은 관계형 모델에서는 없다. 오히려 테이블을 루프로 처리하는 것은 집합 연산을 정면으로 부정하는 행위다.
집합에는 NULL이라는 개념이 없다. 단지 요소가 포함돼 있을 뿐이다. 요소는 존재하면 집합에 포함되고 그렇지 않으면 집합에 해당하는 요소는 포함되지 않는다.
NULL은 값이 존재하지 않거나 알 수 없다는 의미의 특별한 기호이며 값이 아니다. 따라서 NULL을 집합에 포함할 수 없다.
SQL에서 릴레이션의 연산이 가능하다는 것은 릴레이션에 해당하는 테이블이 릴레이션과 공통된 성질을 가져야 한다는 것이다. 즉, 릴레이션과 테이블은 여러 부분에서 차이가 있지만 적어도 테이블을 릴레이션의 성질과 비슷하게 하는 것이 효과적으로 SQL을 작성하기 위한 필수 조건이다.
관계형 모델은 수학(집합론)을 바탕으로 한 강력한 데이터 모델이며 쿼리(질의)의 정확도 역시 수학에 의해 보장된다. 아무리 현실에 맞게 모델을 바꾸더라도 집합이 가진 수학적인 성질은 바뀌지 않는다.
중요한 것은 관계형 모델의 한계를 알고, 관계형 모델을 적용할 수 있는 부분과 그렇지 않은 부분을 파악하는 것이다.
관계형 모델은 집합론을 기초로 한 데이터 모델이며 술어 논리라는 소위 논리학에 기초한 데이터 모델이다.
술어논리는 관계형 모델의 본질이며 논리학을 기반으로 하지 않는 정규화의 설명은 엉터리라고 해도 과언이 아니다.
명제란 어떤 사물에 관해 설명한 문장이 그 의미가 정확한지, 즉 참인지 거짓인지 물을 수 있는 문장이다.
논리학이란 명제의 관계를 연구하는 학문이며, 어떤 명제(한개 또는 여러개)의 참과 거짓을 알고 있을 때 다른 명제의 참과 거짓이 무엇인지 알아내는 데 특화된 학문.
명제의 참과 거짓을 이용해 다른 명제의 참과 거짓을 증명할때 중요한 것은 참과 거짓 값 뿐이며 명제가 가진 다른 의미는 아무 영향을 끼치지 않는다.
명제에서 참과 거짓 이외의 의미를 제거하기 위해 명제를 P나 Q등의 기호로 표현한다.
두 가지 또는 한 개의 명제에서 새로운 참과 거짓을 도출하기 위한 기호를 연결자라고 한다.
연결자는 일반적으로 논리연산이라고 불리며 논리기호는 두 가지 또는 한 가지의 진리값을 가지며 식 전체의 진리값을 고유하게 결정하는 역할을 한다. 이런 성질을 가지는 것을 진리함수라고 한다.
(P ⊃ Q) ⊃ ¬(¬Q ⊃ ¬P)
위의 진리표는 매개변수가 되는 명제의 값에 상관없이 결과가 항상 참이 되는 논리식을 동어반복 또는 항진식이라고 한다.
명제논리에서 동어반복은 언제 어떠한 상황에서도 성립하는 절대적인 법칙, 즉 진리와 같은 것이라고 할 수 있다.
동어반복은 어떤 설명이 바른지 아닌지 증명하는 데 사용하거나 참이 되는 논리식에서 다른 참이 되는 논리식을 도출할 때 사용한다.
명제논리에서 동어반복은 정의돼 있는 것이다.
다음은 명제논리에서 자주 사용되는 정리, 즉 동어반복이다.
동일법칙... P ⊃ P
배중법칙... P ⊃ P
이중부정법칙... P ⊃ P
모순법칙... P ⊃ P
Principle of explosion 법칙... P ⊃ P
대우법칙... P ⊃ P
추이법칙... P ⊃ P
분배법칙... P ⊃ P
드 모르간법칙... P ⊃ P
전건긍정식... P ⊃ P
후건부정식... P ⊃ P
선언적삼단논법... P ⊃ P
각 정리에는 그 정리가 올바른지, 즉 참인 것을 보장하기 위한 전제가 되는 정리가 있어야 한다.
정리는 아무런 전제 없이도 올바르다고 인정하자는 합의하에 정해진 다른 정리의 출발점이 되는 것이다. 이를 공리라고 하며 모든 정리는 공리가 출발점이다. 바꾸어 말하면 정리란 공리에서 도출된 논리적으로 올바른 명제다. 정리의 정확성은 공리에 의해서 보장되고 있는 것이다.
공리는 다양한 정리에 전제로 사용되므로 마음대로 공리를 만들수 없다.
공리는 하나뿐 아니라 여러 개의 명제를 조합하여 성립한다. 공리로 정의된 명제끼리 모순이 없어야 하고 공리는 다뤄지는 주제가 전체를 포괄할 수 있는 것을 가정하여 정의해야 한다. 이처럼 고민하고 정한 공리의 집합을 공리계라고 한다.
하나의 주제를 다루는 공리계는 절대적으로 유일하다고 할 수 없다? 무모순성이나 완전성을 만족시키는 공리계는 몇 가지의 변종이 있을 때도 있다?
명제 논리의 공리계 중 대표적인 것이 사실은 공리가 아닌(공집합) 버전이 있다. 공리는 정의돼있지 않지만, 네개의 연결자(⊃, ¬, ∧, ∨) 각각에 대해 도립과 제거를 위한 다음과 같은 여덜개의 규칙을 정의해 공리계가 성립된다.
스터디에서 나온 내용은 이후에 추가할 예정이다.